package cn.finyzq.ss.games.service.impl;

import cn.finyzq.ss.games.persist.UserMapper;
import cn.finyzq.ss.games.service.RoomService;
import cn.finyzq.ss.games.utils.ResultCode;
import cn.finyzq.ss.games.utils.StringUtils;
import cn.finyzq.ss.games.vo.Player;
import cn.finyzq.ss.games.vo.ResultBean;
import cn.finyzq.ss.games.vo.Room;
import cn.finyzq.ss.games.vo.User;
import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Create Time: 2018年08月05日 13:04
 *
 * @author fin
 */
@Service
public class RoomServiceImpl implements RoomService {

    public static final String MSG_CHAT = "CHAT";
    /** logger */
    private Logger logger = LoggerFactory.getLogger(RoomServiceImpl.class);

    /**
     * 房间信息String：房间号 Room：房间信息
     */
    private Map<String, Room> roomList;

    private Map<Integer, WebSocketSession> userWsGroup;

    @Autowired
    private UserMapper userMapper;

    @PostConstruct
    public void init() {
        roomList = new ConcurrentHashMap<>(16);
        userWsGroup = new ConcurrentHashMap<>(16);
    }

    /**
     * 开房间，如果该用户在另外一个房间，则返回失败并返回所在的房间对象
     *
     * @param user     申请开房用户
     * @param roomType 房间游戏类型
     * @return 开房结果
     */
    @Override
    public ResultBean<Room> openRoom(User user, int roomType) {
        return openRoom(user, roomType, false);
    }

    /**
     * 开房间，如果该用户在另外一个房间，则返回失败并返回所在的房间对象
     *
     * @param user     申请开房用户
     * @param roomType 房间游戏类型
     * @param force    强开 如果存在房间则退出房间并创建新房间 默认false
     * @return 开房结果
     */
    @Override
    public ResultBean<Room> openRoom(User user, int roomType, boolean force) {
        String roomNo = this.findByUser(user);

        // 如果存在房间且不是强开请求，则返回原房间信息
        if (roomNo != null && !force) {
            return new ResultBean<>(ResultCode.USER_ALREADY_HAVE_ROOM, roomList.get(roomNo), "用户已有房间");
        }

        Room room = createRoom(user, roomType, roomNo);
        if (room == null) {
            return new ResultBean<>(ResultCode.CREATE_ROOM_FAIL, "创建房间失败");
        } else {
            return new ResultBean<>(room);
        }
    }

    /**
     * 寻找用户是否存在房间
     *
     * @param user 用户信息
     * @return
     */
    @Override
    public ResultBean findUserRoom(User user) {
        String roomNo = findByUser(user);
        if (roomNo != null) {
            return new ResultBean(roomList.get(roomNo).getRoomNo());
        } else {
            return new ResultBean(ResultCode.ROOM_NOT_FOUND, "该用户不存在房间");
        }
    }

    /**
     * 寻找房间
     *
     * @param roomNo 房间号
     * @return 房间信息
     */
    @Override
    public ResultBean<Room> findRoom(String roomNo) {
        Room room = roomList.get(roomNo);
        if (room == null) {
            return new ResultBean<>(ResultCode.ROOM_NOT_FOUND, "房间不存在或已关闭");
        } else {
            return new ResultBean<>(room);
        }
    }

    /**
     * 处理websocket消息
     * @param message 消息体
     * @param session 来源
     */
    @Override
    public void excuteWebSocketMessage(JSONObject message, WebSocketSession session) {
        for (Integer key : userWsGroup.keySet()) {
            if (session == userWsGroup.get(key)) {
                message.put("user", userMapper.selectByPrimaryKey(key));
            }
        }
        // 没查询到用户
        if (message.get("user") == null) {
            return;
        }
        doExcute(message);
    }

    /**
     * 添加用户ws信息
     *
     * @param userId
     * @param session
     */
    @Override
    public void addUserWsSession(Integer userId, WebSocketSession session) {
        this.userWsGroup.put(userId, session);
    }

    /**
     * 寻找房间 成功则返回房间号
     *
     * @param user 索引用户
     * @return roomNo
     */
    private String findByUser(User user) {
        if (roomList == null || roomList.size() == 0) {
            return null;
        }

        for (String s : roomList.keySet()) {
            Room room = roomList.get(s);
            if(room.existUser(user) && room.getRoomStatus() != Room.CLOSE){
                return s;
            }
        }
        return null;
    }

    /**
     * 创建房间，如果传入一个存在的房间索引，则删除该房间用户且重置房间信息
     *
     * @param user     用户
     * @param roomType 游戏类型
     * @param roomNo   房间号
     * @return 生成房间信息
     */
    private Room createRoom(User user, int roomType, String roomNo) {

        // 离开房间处理
        if (roomNo != null) {
            Room room = roomList.get(roomNo);
            room.getParticipants().remove(user);
            if (room.getParticipants().size() == 0) {
                room.setRoomStatus(Room.CLOSE);
                // 不对房间进行移除，采用清理模式
                //                roomList.remove(room);
            } else if (room.getOwner().equals(user)) {
                room.setOwner(room.getParticipants().get(0));
            }
        }

        // 对房间进行创建并登记
        Room room = new Room();
        room.setOwner(user);
        Player player = new Player();
        player.setOpenid(user.getOpenid());
        player.setAvatar(user.getAvatar());
        player.setNickname(user.getNickname());
        player.setId(user.getId());

        room.addParticipant(player);
        room.setRoomNo(StringUtils.UUID());
        room.setRoomStatus(Room.READY);
        room.setGameType(roomType);
        roomList.put(room.getRoomNo(), room);
        return room;
    }

    private void chat(JSONObject msg){
        String roomNo = msg.getString("roomNo");
        for (User user : roomList.get(roomNo).getParticipants()) {
            WebSocketSession session = userWsGroup.get(user.getId());
            try {
                session.sendMessage(new TextMessage(msg.toJSONString()));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private void doExcute(JSONObject message) {

        logger.info("Receive message from {}" , message.getObject("user", User.class).getNickname());
        logger.info(message.toJSONString());
        switch (message.getString("msgType")) {
            case MSG_CHAT:
                chat(message);
                break;
            default:
                chat(message);
                break;
        }


    }



}
